package pocisk;

/**
 *
 * @author Maciej
 */
public class Minimum1D { // klasa do poszukiwań minimum funkcji jednowymiarowej - do metody numerycznej Hooka

    double result, tau, start, lastres, currentres, move;
    int dir;
    Hooke hook;

    Minimum1D(Hooke h) {
        hook = h;
    }

    public double result() {
        return result;
    }

    public void gradcompute(double start, double smove, double minmove, int maxiter, double eps) {
        move = smove * 4;
        int goodmoves = 0;
        int iter = 0;
        tau = start;
        currentres = hook.callTau(tau);
        lastres = currentres + 100;

        while (iter < maxiter && move > minmove && Math.abs(lastres - currentres) > eps) { //dopóki nie przekroczono ograniczenia iteracji, wielkość kroku nie spadła poniżej minimum, oraz różnica dwóch ostatnich wyników jest większa od epsilon
            if (dir == 0) { //w tym ifie sprawdź w którą stronę bardziej opłaca się poruszać - na plus czy minus oraz zmniejsza się krok
                move /= 4;
                double down = hook.callTau(tau - move);
                double up = hook.callTau(tau + move);
                if (up < down) {
                    dir = 1;
                } else {
                    dir = -1;
                }
            } else if (dir == 1) { // jeśli idziesz na plusy
                if (goodmoves >= 3) { //jeśli ostatnie 3 kroki były pomyślne zwiększ długość kroku by zaoszczędzić na ilości wywołań symulacji
                    move *= 2;
                    goodmoves = 0;
                }
                tau += move;
                double tempres = hook.callTau(tau);
                if (tempres < currentres) { // sprawdz czy krok dodatni się opłacał, wykonaj jeśli obecny wynik jest mniejszy od zapamiętanego
                    goodmoves++;
                    lastres = currentres;
                    currentres = tempres;
                } else { //jeśli był to zły krok - przywróc stare tau i szukaj lepszego tau z mniejszym krokiem
                    tau -= move;
                    dir = 0;
                    goodmoves = 0;
                }
            } else if (dir == -1) { //jeśli idziesz na minusy
                if (goodmoves >= 3) { //jeśli ostatnie 3 kroki były pomyślne zwiększ długość kroku by zaoszczędzić na ilości wywołań symulacji
                    move *= 2;
                    goodmoves = 0;
                    //System.out.println("BONUS, move="+move);
                }
                tau -= move;
                double tempres = hook.callTau(tau);
                if (tempres < currentres) { // sprawdz czy krok się opłacał, wykonaj jeśli obecny wynik jest mniejszy od zapamiętanego
                    goodmoves++;
                    lastres = currentres;
                    currentres = tempres;
                } else { //jeśli był to zły krok - przywróc stare tau i szukaj lepszego tau z mniejszym krokiem
                    tau += move;
                    goodmoves = 0;
                    dir = 0;
                }
            }
            iter++;
        }
        result = tau;
    }
}
